<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>待办事项</title>
    <link
      href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/css/all.min.css"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="task03_todolist.css" />
  </head>
  <body>
    <h1>待办事项</h1>
    <p class="subtitle">简单高效地管理你的任务</p>
    <div class="todo-container" id="todoContainer">
      <div class="todo-input-group">
        <input type="text" id="todoInput" placeholder="添加新的待办事项..." />
        <button id="addBtn"><i class="fa-solid fa-plus"></i> 添加</button>
      </div>
      <div class="filters">
        <button data-filter="all" class="active">全部</button>
        <button data-filter="active">未完成</button>
        <button data-filter="completed">已完成</button>
      </div>
      <ul id="todoList"></ul>
      <div class="footer" id="footerText"></div>
    </div>

    <script>
      // 定义待办事项应用的主类
      class TodoList {
        constructor() {
          // 从本地存储读取已有的待办事项（若无则设为空数组）
          this.todos = JSON.parse(localStorage.getItem("todos") || "[]");

          // 当前筛选状态：all（全部）/ active（未完成）/ completed（已完成）
          this.filter = "all";

          // 获取页面中主要的 DOM 元素
          this.todoInput = document.getElementById("todoInput");
          this.todoList = document.getElementById("todoList");
          this.footerText = document.getElementById("footerText");
          this.todoContainer = document.getElementById("todoContainer");

          // 初始化事件绑定与初始渲染
          this.init();
        }

        // 初始化函数，绑定事件并首次渲染
        init() {
          // 点击“添加”按钮时添加新任务
          document
            .getElementById("addBtn")
            .addEventListener("click", () => this.addTodo());

          // 在输入框中按下 Enter 键也能添加任务
          this.todoInput.addEventListener("keypress", (e) => {
            if (e.key === "Enter") this.addTodo();
          });

          // 给筛选按钮绑定点击事件，实现任务分类过滤
          document.querySelectorAll(".filters button").forEach((btn) => {
            btn.addEventListener("click", () => {
              // 移除其他按钮的高亮状态
              document
                .querySelectorAll(".filters button")
                .forEach((b) => b.classList.remove("active"));
              // 当前按钮高亮
              btn.classList.add("active");
              // 记录筛选类型
              this.filter = btn.dataset.filter;
              // 重新渲染列表
              this.render();
            });
          });

          // 初始页面渲染
          this.render();
        }

        // 添加新的待办事项
        addTodo() {
          const text = this.todoInput.value.trim(); // 获取输入的文本内容
          if (!text) return alert("请输入待办事项！"); // 防止添加空项

          // 创建新任务对象
          const newTodo = { id: Date.now(), text, completed: false };

          // 添加到任务数组中
          this.todos.push(newTodo);

          // 保存到本地存储
          this.save();

          // 清空输入框
          this.todoInput.value = "";

          // 重新渲染，并标记为“添加”状态以启用淡入动画
          this.render(true);
        }

        // 切换任务完成状态（打勾或取消）
        toggleTodo(id) {
          // 遍历数组，找到对应任务切换 completed 状态
          this.todos = this.todos.map((todo) =>
            todo.id === id ? { ...todo, completed: !todo.completed } : todo
          );
          this.save(); // 保存修改
          this.render(); // 重新渲染
        }

        // 删除指定任务（带动画）
        deleteTodo(id, li) {
          // 先添加淡出动画类
          li.classList.add("fade-out");

          // 等动画执行完再真正删除元素
          li.addEventListener(
            "transitionend",
            () => {
              // 从任务数组中移除该项
              this.todos = this.todos.filter((todo) => todo.id !== id);
              this.save(); // 保存最新数据
              this.render(); // 重新渲染
            },
            { once: true } // 只执行一次
          );
        }

        // 保存任务数组到本地存储
        save() {
          localStorage.setItem("todos", JSON.stringify(this.todos));
        }

        // 渲染任务列表
        // 参数 isAdding 表示是否是新添加的任务，用于触发动画
        render(isAdding = false) {
          // 记录当前容器高度，用于平滑过渡动画
          const prevHeight = this.todoContainer.offsetHeight;

          // 清空原有列表内容
          this.todoList.innerHTML = "";

          // 根据当前筛选状态过滤任务
          let filteredTodos = this.todos;
          if (this.filter === "active")
            filteredTodos = this.todos.filter((t) => !t.completed);
          if (this.filter === "completed")
            filteredTodos = this.todos.filter((t) => t.completed);

          // 遍历任务数组，生成每一条任务项
          filteredTodos.forEach((todo) => {
            const li = document.createElement("li");

            // 若任务已完成，则加上样式
            if (todo.completed) li.classList.add("completed");

            // 若是刚添加的任务，添加淡入动画
            if (isAdding && todo.id === this.todos[this.todos.length - 1].id)
              li.classList.add("fade-in");

            // 创建复选框
            const checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.checked = todo.completed;
            checkbox.addEventListener("change", () => this.toggleTodo(todo.id));

            // 创建任务文字标签
            const label = document.createElement("span");
            label.textContent = todo.text;

            // 创建删除按钮
            const delBtn = document.createElement("button");
            delBtn.innerHTML = '<i class="fa-solid fa-trash-can"></i>';
            delBtn.addEventListener("click", () =>
              this.deleteTodo(todo.id, li)
            );

            // 将子元素组装进列表项
            li.appendChild(checkbox);
            li.appendChild(label);
            li.appendChild(delBtn);

            // 添加到页面列表
            this.todoList.appendChild(li);
          });

          // 统计任务完成情况
          const uncompleted = this.todos.filter((t) => !t.completed).length;
          const completed = this.todos.filter((t) => t.completed).length;
          const total = this.todos.length;

          // 根据筛选状态动态显示底部文字
          if (this.filter === "completed") {
            this.footerText.textContent = `已完成 ${completed} 项，共 ${total} 项`;
          } else if (this.filter === "active") {
            this.footerText.textContent = `未完成 ${uncompleted} 项，共 ${total} 项`;
          } else {
            this.footerText.textContent = `未完成 ${uncompleted} 项，共 ${total} 项`;
          }

          // 容器高度平滑变化动画
          const newHeight = this.todoContainer.scrollHeight;
          this.todoContainer.style.height = prevHeight + "px";
          requestAnimationFrame(() => {
            this.todoContainer.style.height = newHeight + "px";
          });
          setTimeout(() => {
            this.todoContainer.style.height = "auto"; // 动画结束后恢复自适应
          }, 400);
        }
      }

      // 创建应用实例并启动
      new TodoList();
    </script>
  </body>
</html>
